

package com.sihai.gateway.support;

import org.springframework.util.FileCopyUtils;

import java.io.*;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Caching {@link HttpServletRequest}, because {@link ServletInputStream} just can read once.
 *
 * @author sihai
 */
public class CacheRequestWrapper extends HttpServletRequestWrapper {
  // 参数字节数组
  private byte[] requestBody;
  // Http请求对象
  private HttpServletRequest request;
  public CacheRequestWrapper(HttpServletRequest request) {
    super(request);
    this.request = request;
  }

  // @Override
  // public ServletInputStream getInputStream() throws IOException {
  //   ServletInputStream inputStream = super.getInputStream();
  //   return new ServletInputStream() {
  //
  //     @Override
  //     public boolean isFinished() {
  //       return false;
  //     }
  //
  //     @Override
  //     public boolean isReady() {
  //       return false;
  //     }
  //
  //     @Override
  //     public void setReadListener(ReadListener listener) {
  //       // NOP
  //     }
  //
  //     @Override
  //     public int read() throws IOException {
  //       return inputStream.read();
  //     }
  //   };
  // }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    /**
     * 每次调用此方法时将数据流中的数据读取出来，然后再回填到InputStream之中
     * 解决通过@RequestBody和@RequestParam（POST方式）读取一次后控制器拿不到参数问题
     */
    if (null == this.requestBody) {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ServletInputStream inputStream = request.getInputStream();
      System.out.println(inputStream);
      FileCopyUtils.copy(inputStream,baos);
      this.requestBody = baos.toByteArray();
    }

    final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
    return new ServletInputStream() {

      @Override
      public boolean isFinished() {
        return false;
      }

      @Override
      public boolean isReady() {
        return false;
      }

      @Override
      public void setReadListener(ReadListener listener) {

      }

      @Override
      public int read() {
        return bais.read();
      }
    };
  }

  public byte[] getRequestBody() {
    return requestBody;
  }

  @Override
  public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(this.getInputStream()));
  }
}
